/*
 * 文件名： PabApayHelper.java
 * 
 * 工程名称: bis-bank-pab
 *
 * Gopay
 *
 * 创建日期： 2017年8月14日
 *
 * Copyright(C) 2017, by www.gopay.com.cn Inc.All rights reserved.
 *
 * 原始作者: 宣广海
 *
 */
package com.gopay.bis.pab.apay.operation;

import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONObject;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.exception.GopayException;
import com.gopay.common.util.FastJsonUtil;

/**
 * 平安银行聚合支付操作
 *
 * @author 宣广海
 *
 * @version
 *
 * @since 2017年8月14日
 */
public class PabApayHelper {
	private static Logger logger = LoggerFactory.getLogger(PabApayHelper.class);
	private static String CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";
	private static String KEY_ALGORITHM = "AES";

	/**
	 * 
	 * 功能描述：签名
	 *
	 * @param veriDataMap
	 * @return
	 * @throws GopayException
	 * 
	 * @author 宣广海
	 *
	 * @since 2017年8月14日
	 *
	 * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
	 */
	public String sign(Map<String, String> veriDataMap) throws GopayException {
		String sortStr = null;
		String sign = null;
		try {
			/**
			 * 1 A~z排序(加上open_key)
			 */
			sortStr = sort(veriDataMap);
			/**
			 * 2 sha1加密(小写)
			 */
			String sha1 = methodSHA1(sortStr);

			/**
			 * 3 md5加密(小写)
			 */
			sign = Md5Util.methodMD5Encode(sha1).toLowerCase();
		} catch (Exception e) {
			logger.error("平安银行聚合支付签名错误！" + e);
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E7025);
		}
		return sign;
	}

	public String signRSA(Map<String, String> veriDataMap, String privateKey) throws GopayException {
		String sortStr = null;
		String sign = null;
		try {
			/**
			 * 1 A~z排序(加上open_key)
			 */
			sortStr = sort(veriDataMap);
			sign = TLinxRSACoder.sign(sortStr.getBytes("utf-8"), privateKey);
		} catch (Exception e) {
			logger.error("平安银行聚合支付签名错误！" + e);
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E7025);
		}
		return sign;
	}
	public String signMerchant(Map<String, String> veriDataMap, String privateKey) throws GopayException {
		String sortStr = null;
		String sign = null;
		try {
			/**
			 * 1 A~z排序(加上open_key)
			 */
			sortStr = sort(veriDataMap);
			/**
			 * 2 sha1加密(小写)
			 */
			String sha1 = methodSHA1(sortStr);
			/** 
             * 3 RSA加密(小写),二进制转十六进制
             */
			sign = TLinxRSACoder.sign(sha1.getBytes("utf-8"), privateKey);
		} catch (Exception e) {
			logger.error("平安银行聚合支付签名错误！" + e);
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E7025);
		}
		return sign;
	}
	/**
	 * 
	 * 功能描述：验签方法
	 *
	 * @param resultStr
	 * @return
	 * @throws GopayException
	 * 
	 * @author 宣广海
	 *
	 * @since 2017年8月15日
	 *
	 * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
	 */
	@SuppressWarnings("unchecked")
	public Boolean verify(JSONObject respObject, String openKey) throws GopayException {
		String respSign = respObject.get("sign").toString();
		respObject.remove("sign"); 
		respObject.put("open_key", openKey);
		Map<String, String> veriDataMap = FastJsonUtil.stringToCollect(respObject.toJSONString());
		 // 按A~z排序，串联成字符串，先进行sha1加密(小写)，再进行md5加密(小写)，得到签名
		String veriSign = sign(veriDataMap);
		if (respSign.equals(veriSign)) {
			logger.info("=====验签成功=====");
			return true;
		} else {
			logger.info("=====验签失败=====");
		}
		return false;
	}
	public Boolean verifyMerchant(JSONObject respObject, String publicKey)
			throws GopayException {
		String respSign = respObject.get("sign").toString();
		// 删除sign节点
		respObject.remove("sign"); 
		try {
			String rspparm = sort(FastJsonUtil.stringToCollect(respObject.toString())); 
            String sha1    = methodSHA1(rspparm);
			if (TLinxRSACoder.verify(sha1.getBytes(), publicKey, respSign)) {
				logger.info("=====验签成功=====");
				return true;
			} else {
				logger.info("=====验签失败=====");
			}
		} catch (Exception ex) {
			logger.info("=====验签出现问题=====" + ex);
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E7025);
		}
		return false;
	}
	public Boolean verifyRefund(JSONObject respObject, String openKey, String publicKey, String privateKey)
			throws GopayException {
		String respSign = respObject.get("sign").toString();
		// 删除sign节点
		respObject.remove("sign");
		respObject.put("open_key", openKey);
		Map<String, String> veriDataMap = FastJsonUtil.stringToCollect(respObject.toJSONString());
		try {
			String veriSign = sign(veriDataMap);
			if (respSign.equals(veriSign)) {
				logger.info("=====验签成功=====");
				return true;
			} else {
				logger.info("=====验签失败=====");
			}
		} catch (Exception ex) {
			logger.info("=====验签出现问题=====" + ex);
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E7025);
		}
		return false;
	}

	public String handleSign(TreeMap<String, String> postmap, String openKey) throws GopayException {
		Map<String, String> veriDataMap = new HashMap<String, String>();
		veriDataMap.putAll(postmap);
		veriDataMap.put("open_key", openKey);
		return sign(veriDataMap);
	}

	public String handleMerchantSign(TreeMap<String, String> getmap, TreeMap<String, String> datamap,String privateKey)
			throws GopayException {
		Map<String, String> veriDataMap = new HashMap<String, String>();
		veriDataMap.putAll(getmap);
		veriDataMap.putAll(datamap);
		// 签名
		return signMerchant(veriDataMap, privateKey);
	}

	public String handleSignRSA(TreeMap<String, String> postmap, String openKey, String privateKey)
			throws GopayException {
		Map<String, String> veriDataMap = new HashMap<String, String>();
		veriDataMap.putAll(postmap);
		veriDataMap.put("open_key", openKey);
		// 签名
		return signRSA(veriDataMap, privateKey);
	}

	public String decrypt(String sSrc, String sKey) throws Exception {
		SecretKeySpec skeySpec = new SecretKeySpec(sKey.getBytes("ASCII"), KEY_ALGORITHM);
		Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
		cipher.init(2, skeySpec);
		byte[] encrypted1 = hex2byte(sSrc);
		byte[] original = cipher.doFinal(encrypted1);
		return new String(original);
	}

	/**
	 * 
	 * 功能描述：
	 *
	 * @param sSrc
	 *            需要加密的请求数据，json串
	 * @param sKey
	 *            进件成功后返回的密钥
	 * @return
	 * @throws Exception
	 * 
	 * @author 宣广海
	 *
	 * @since 2017年8月14日
	 *
	 * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
	 */
	public String encrypt(String sSrc, String sKey) throws Exception {
		try {
			SecretKeySpec skeySpec = new SecretKeySpec(sKey.getBytes("ASCII"), KEY_ALGORITHM);
			Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
			cipher.init(1, skeySpec);
			byte[] encrypted = cipher.doFinal(sSrc.getBytes("UTF-8"));
			return byte2hex(encrypted);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			throw new Exception();
		}
	}

	private static byte[] hex2byte(String strhex) {
		if (strhex == null) {
            return null;
        }

		int l = strhex.length();
		if (l % 2 == 1) {
            return null;
        }

		byte[] b = new byte[l / 2];
		for (int i = 0; i != l / 2; ++i) {
            b[i] = (byte) Integer.parseInt(strhex.substring(i * 2, i * 2 + 2), 16);
        }

		return b;
	}

	private String byte2hex(byte[] b) {
		String hs = "";
		String stmp = "";
		for (int n = 0; n < b.length; ++n) {
			stmp = Integer.toHexString(b[n] & 0xFF);
			if (stmp.length() == 1) {
                hs = hs + "0" + stmp;
            } else {
                hs = hs + stmp;
            }
		}

		return hs.toUpperCase();
	}

	/**
	 * 
	 * 功能描述：排序
	 *
	 * @param paramMap
	 * @return
	 * @throws Exception
	 * 
	 * @author 宣广海
	 *
	 * @since 2017年8月14日
	 *
	 * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
	 */
	@SuppressWarnings("rawtypes")
	private String sort(Map paramMap) throws Exception {
		String sort = "";
		MapUtil signMap = new MapUtil();
		if (paramMap != null) {
			String key;
			for (Iterator it = paramMap.keySet().iterator(); it.hasNext();) {
				key = (String) it.next();
				String value = ((paramMap.get(key) != null) && (!("".equals(paramMap.get(key).toString()))))
						? paramMap.get(key).toString() : "";
				signMap.put(key, value);
			}
			signMap.sort();
			for (Iterator it = signMap.keySet().iterator(); it.hasNext();) {
				key = (String) it.next();
				sort = sort + key + "=" + signMap.get(key).toString() + "&";
			}
			if ((sort != null) && (!("".equals(sort)))) {
				sort = sort.substring(0, sort.length() - 1);
			}
		}
		return sort;
	}

	public String methodSHA1(String decript) throws GopayException {
		try {
			MessageDigest digest = MessageDigest.getInstance("SHA-1");
			digest.update(decript.getBytes("UTF-8"));
			byte[] messageDigest = digest.digest();
			StringBuilder hexString = new StringBuilder();
			for (byte message : messageDigest) {
				String shaHex = Integer.toHexString(message & 0xFF);
				if (shaHex.length() < 2) {
                    hexString.append(0);
                }

				hexString.append(shaHex);
			}
			return hexString.toString().toLowerCase();
		} catch (Exception e) {
			logger.error("平安银行聚合支付签名错误！" + e);
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E7025);
		}
	}
}
